package com.qsd.doc4jsimpple.factory;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.jayway.jsonpath.JsonPath;
import com.qsd.doc4jsimpple.DocxPainter;
import com.qsd.doc4jsimpple.constants.ComponentTypeEnum;
import com.qsd.doc4jsimpple.constants.MultiLevelTypeEnum;
import com.qsd.doc4jsimpple.item.*;
import com.qsd.doc4jsimpple.style.DocxStyle;
import com.qsd.doc4jsimpple.util.CollectionTool;
import com.qsd.doc4jsimpple.util.RichTextHelper;
import lombok.NonNull;
import net.minidev.json.JSONArray;
import org.apache.commons.lang3.StringUtils;
import org.docx4j.dml.CTPositiveSize2D;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.model.table.TblFactory;
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
import org.docx4j.wml.*;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static com.qsd.doc4jsimpple.style.DocxStyle.getStyleByAttrs;

/**
 * @author : xujunxia
 * @version : 1.0.0
 * @description : 多克斯工厂
 * <a href="http://webapp.docx4java.org/OnlineDemo/ecma376/WordML/index.html">docx4j支持的word标签</a>
 * 可以在该文档查看相关样式的xml标签，docx4j都有对应的类，按其嵌套方式去组装就能有相同效果
 * @createTime : 2022-08-20 15:58:01
 */
public class DocxFactory extends StyleFactory {


    private static final String endpoint = "http://192.168.110.40:9000/";

    private static final String bucketName = "smartreport";

    /**
     * 新页面
     *
     * @return {@link P}
     */
    public static P newPage() {
        P p = factory.createP();
        R r = factory.createR();
        Br br = factory.createBr();
        br.setType(STBrType.PAGE);
        r.getContent().add(br);
        p.getContent().add(r);
        return p;
    }



    public static List<P> createBUlletList(DocxPainter docxPainter,DocxComponent docxComponent,Integer bulletCount) {


        String orderListJsonStr = JSON.toJSONString(docxComponent);
        JSONArray itemList = JsonPath.read(orderListJsonStr, "$.content[?(@.type == 'listItem')]");
        String jsonStr = itemList.toJSONString();
        List<DocxComponent> componentList = com.alibaba.fastjson.JSONArray.parseArray(jsonStr, DocxComponent.class);
       return createBUlletListItem(orderListJsonStr,componentList, docxPainter,bulletCount);
    }


    public static List<P> createOrderedList(DocxPainter docxPainter,DocxComponent docxComponent,Integer orderCount) {
        String orderListJsonStr = JSON.toJSONString(docxComponent);
        JSONArray itemList = JsonPath.read(orderListJsonStr, "$.content[?(@.type == 'listItem')]");
        String jsonStr = itemList.toJSONString();
        List<DocxComponent> componentList = com.alibaba.fastjson.JSONArray.parseArray(jsonStr, DocxComponent.class);
        return createOrderListItem(orderListJsonStr,componentList,docxPainter,orderCount);
    }

    public static List<P> createOrderListItem( String json,List<DocxComponent> componentList,DocxPainter docxPainter,Integer orderCount){
        if(CollUtil.isNotEmpty(componentList)){

            List<P> pList = new ArrayList<P>(componentList.size());
            JSONArray itemList = JsonPath.read(json, "$..content[?(@.type == 'paragraph')]");
            String jsonStr = itemList.toJSONString();
            List<DocxComponent> paragraphList = com.alibaba.fastjson.JSONArray.parseArray(jsonStr, DocxComponent.class);
            for(DocxComponent component : paragraphList){
                P pa = createParaOnly();
                List<DocxComponent> runList =   component.getContent();
                if(CollectionUtil.isNotEmpty(runList)){
                    for(DocxComponent run : runList){
                        appendParagraphRun(pa,run,docxPainter);
                    }
                }
                pList.add(pa);
            }

            //增加编号列表设置部分，注意，一定要增加到MainDocumentPart中，否则会出现引用不成功的情况

            try {

                Numbering numbering = docxPainter.getNumbering();
                if(Objects.isNull(numbering)){
                    numbering = new Numbering();
                }
                Map<Integer,List<Integer>> orderListMap = docxPainter.getOrderMap();
                if(CollectionUtil.isNotEmpty(orderListMap)) {
                    List<Integer> numberIdList = orderListMap.get(orderCount);
                    for(int i=0;i< numberIdList.size();i++){
                        appendNum(BigInteger.valueOf(orderCount), BigInteger.valueOf(numberIdList.get(i)),numbering);
                    }
                }


                //遍历所有支持的列表格式
                //注意：numId不能为0，否则不显示列表

            } catch (Exception e) {
                e.printStackTrace();
            }



            for(int j=0;j<pList.size();j++){
                PPrBase.NumPr numPr = new PPrBase.NumPr();
                PPrBase.NumPr.NumId numid = new PPrBase.NumPr.NumId();
                numid.setVal(BigInteger.valueOf(j+1));
                numPr.setNumId(numid);
                PPrBase.NumPr.Ilvl ilvl = new PPrBase.NumPr.Ilvl();
                ilvl.setVal(BigInteger.ONE);
                numPr.setIlvl(ilvl);
                pList.get(j).getPPr().setNumPr(numPr);
            }
            return pList;
        }

        return null;

    }


    public static List<P> createBUlletListItem( String json,List<DocxComponent> componentList,DocxPainter docxPainter,Integer bulletCount){
        if(CollUtil.isNotEmpty(componentList)){

            List<P> pList = new ArrayList<P>(componentList.size());
            JSONArray itemList = JsonPath.read(json, "$..content[?(@.type == 'paragraph')]");
            String jsonStr = itemList.toJSONString();
            List<DocxComponent> paragraphList = com.alibaba.fastjson.JSONArray.parseArray(jsonStr, DocxComponent.class);
            for(DocxComponent component : paragraphList){
                P pa = createParaOnly();
                List<DocxComponent> runList =   component.getContent();
                if(CollectionUtil.isNotEmpty(runList)){
                    for(DocxComponent run : runList){
                        appendParagraphRun(pa,run,docxPainter);
                    }
                }
                pList.add(pa);
            }

            //增加编号列表设置部分，注意，一定要增加到MainDocumentPart中，否则会出现引用不成功的情况

            try {

                Numbering numbering = docxPainter.getNumbering();
                if(Objects.isNull(numbering)){
                    numbering = new Numbering();
                }

               Map<Integer,List<Integer>> bulletListMap = docxPainter.getBulletMap();
                if(CollectionUtil.isNotEmpty(bulletListMap)){
                    List<Integer> numberIdList =  bulletListMap.get(bulletCount);
                    for(int i=0;i< numberIdList.size();i++){
                        appendNum(BigInteger.valueOf(bulletCount), BigInteger.valueOf(numberIdList.get(i)),numbering);
                    }
                }


                //遍历所有支持的列表格式
                //注意：numId不能为0，否则不显示列表

            } catch (Exception e) {
                e.printStackTrace();
            }

            Map<Integer,List<Integer>> bulletListMap = docxPainter.getBulletMap();
            List<Integer> numberIdList =  bulletListMap.get(bulletCount);
            for(int j=0;j<pList.size();j++){
                PPrBase.NumPr numPr = new PPrBase.NumPr();
                PPrBase.NumPr.NumId numid = new PPrBase.NumPr.NumId();
                numid.setVal(BigInteger.valueOf(numberIdList.get(j)));
                numPr.setNumId(numid);
                PPrBase.NumPr.Ilvl ilvl = new PPrBase.NumPr.Ilvl();
                ilvl.setVal(BigInteger.ONE);
                numPr.setIlvl(ilvl);
                pList.get(j).getPPr().setNumPr(numPr);
            }
            return pList;
        }

        return null;

    }

    public static void appendNum(BigInteger abstractNumId,BigInteger numberId, Numbering numbering){
        Numbering.Num.AbstractNumId anid = new Numbering.Num.AbstractNumId();
        anid.setVal(abstractNumId);
        Numbering.Num num = new Numbering.Num();
        num.setAbstractNumId(anid);
        num.setNumId(numberId); //此处NumId不能为0，必须为正整数
        //将Num增加到Numbering中
        numbering.getNum().add(num);
    }

    public static void appenLvlNew(BigInteger abstractNumId, Numbering numbering,DocLvl docLvl,DocxPainter docxPainter) {
        //首先定义AbstractNum部分
        Numbering.AbstractNum an = new Numbering.AbstractNum();

        an.setAbstractNumId(abstractNumId);
        an.setMultiLevelType(MultiLevelTypeEnum.SINGLE_LEVEL);

        //定义0级，即最高一级的编号
        //只定义这一个级别
        Lvl lvl = new Lvl();
        lvl.setIlvl(docLvl.getLevel());

        //设置开始序号，如果不设置为1的话默认为0，可能出现某些格式的序号没有0值显示
        Lvl.Start start = new Lvl.Start();
        start.setVal(docLvl.getStart());
        lvl.setStart(start);

        //设置显示文本内容，如果不设置的话将不显示编号
        Lvl.LvlText lvltext = new Lvl.LvlText();
        //表示显示第一级编号，后面跟一个“.”
        //  lvltext.setVal("\u2022");
        lvltext.setVal(docLvl.getValueTemplate());
        lvl.setLvlText(lvltext);


        RPr rPr = new RPr();
        HpsMeasure sz = new HpsMeasure();
        sz.setVal(docLvl.getDocLvlFormat().getContentPound()); // 设置圆点大小为36磅
        rPr.setSz(sz);
        rPr.setSzCs(sz);
        Color color = new Color();
        color.setVal(docLvl.getDocLvlFormat().getColor()); // 设置圆点颜色为红色，RGB值为FF0000
        rPr.setColor(color);
        lvl.setRPr(rPr);
        //将Lvl增加到AbstractNum中
        an.getLvl().add(lvl);



        //将AbstractNum增加到Numbering中
        numbering.getAbstractNum().add(an);

        //设置一个Num的实例，通过AbstractNumId引用刚定义的AbstractNum
        Numbering.Num.AbstractNumId anid = new Numbering.Num.AbstractNumId();
        anid.setVal(abstractNumId);


        List<Numbering.AbstractNum> abstractNumList =  docxPainter.getAbstractNumList();
        if(CollectionUtil.isNotEmpty(abstractNumList)){
            abstractNumList.add(an);
            docxPainter.setAbstractNumList(abstractNumList);
        }else{
            abstractNumList = new ArrayList<>();
            abstractNumList.add(an);
            docxPainter.setAbstractNumList(abstractNumList);
        }


        List<Numbering.Num.AbstractNumId> abstractNumIdList =  docxPainter.getAbstractNumIdList();
        if(CollectionUtil.isNotEmpty(abstractNumIdList)){
            abstractNumIdList.add(anid);
            docxPainter.setAbstractNumIdList(abstractNumIdList);
        }else{
            abstractNumIdList = new ArrayList<>();
            abstractNumIdList.add(anid);
            docxPainter.setAbstractNumIdList(abstractNumIdList);
        }
    }

    public static void addAbstractNumFormat(BigInteger abstractNumId, Numbering numbering,DocLvl docLvl,DocxPainter docxPainter) {
        //首先定义AbstractNum部分
        Numbering.AbstractNum an = new Numbering.AbstractNum();

        an.setAbstractNumId(abstractNumId);
        an.setMultiLevelType(MultiLevelTypeEnum.SINGLE_LEVEL);

        //定义0级，即最高一级的编号
        //只定义这一个级别
        Lvl lvl = new Lvl();
        lvl.setIlvl(docLvl.getLevel());

        //设置开始序号，如果不设置为1的话默认为0，可能出现某些格式的序号没有0值显示
        Lvl.Start start = new Lvl.Start();
        start.setVal(docLvl.getStart());
        lvl.setStart(start);

        //设置显示文本内容，如果不设置的话将不显示编号
        Lvl.LvlText lvltext = new Lvl.LvlText();
        //表示显示第一级编号，后面跟一个“.”
        //  lvltext.setVal("\u2022");
        lvltext.setVal(docLvl.getValueTemplate());
        lvl.setLvlText(lvltext);


        RPr rPr = new RPr();
        HpsMeasure sz = new HpsMeasure();
        sz.setVal(docLvl.getDocLvlFormat().getContentPound()); // 设置圆点大小为36磅
        rPr.setSz(sz);
        rPr.setSzCs(sz);
        Color color = new Color();
        color.setVal(docLvl.getDocLvlFormat().getColor()); // 设置圆点颜色为红色，RGB值为FF0000
        rPr.setColor(color);
        lvl.setRPr(rPr);
        //将Lvl增加到AbstractNum中
        an.getLvl().add(lvl);



        //将AbstractNum增加到Numbering中
        numbering.getAbstractNum().add(an);

        //设置一个Num的实例，通过AbstractNumId引用刚定义的AbstractNum
        Numbering.Num.AbstractNumId anid = new Numbering.Num.AbstractNumId();
        anid.setVal(abstractNumId);

        List<Numbering.AbstractNum> abstractNumList =  docxPainter.getAbstractNumList();
        if(CollectionUtil.isNotEmpty(abstractNumList)){
            abstractNumList.add(an);
            docxPainter.setAbstractNumList(abstractNumList);
        }else{
            abstractNumList = new ArrayList<>();
            abstractNumList.add(an);
            docxPainter.setAbstractNumList(abstractNumList);
        }


        List<Numbering.Num.AbstractNumId> abstractNumIdList =  docxPainter.getAbstractNumIdList();
        if(CollectionUtil.isNotEmpty(abstractNumIdList)){
            abstractNumIdList.add(anid);
            docxPainter.setAbstractNumIdList(abstractNumIdList);
        }else{
            abstractNumIdList = new ArrayList<>();
            abstractNumIdList.add(anid);
            docxPainter.setAbstractNumIdList(abstractNumIdList);
        }
    }



    public static void appendListBody(Body body,String json, List<DocxComponent> componentList,DocxPainter docxPainter){
        List<P> pList = new ArrayList<P>(componentList.size());
        JSONArray itemList = JsonPath.read(json, "$..content[?(@.type == 'paragraph')]");
        String jsonStr = itemList.toJSONString();
        List<DocxComponent> paragraphList = com.alibaba.fastjson.JSONArray.parseArray(jsonStr, DocxComponent.class);
        for(DocxComponent component : paragraphList){
            P pa = createParaOnly();
            List<DocxComponent> runList =   component.getContent();
            if(CollectionUtil.isNotEmpty(runList)){
                for(DocxComponent run : runList){
                    appendParagraphRun(pa,run,docxPainter);
                }
            }
            pList.add(pa);
        }


        PPrBase.NumPr numpr = new PPrBase.NumPr();
        PPrBase.NumPr.NumId numid = new PPrBase.NumPr.NumId();
        numid.setVal(BigInteger.valueOf(1));
        numpr.setNumId(numid);
        PPrBase.NumPr.Ilvl ilvl = new PPrBase.NumPr.Ilvl();
        ilvl.setVal(BigInteger.ZERO);
        numpr.setIlvl(ilvl);

        for(P paragaph:pList){
            paragaph.getPPr().setNumPr(numpr);
            body.getContent().add(paragaph);
        }
    }


    public static P createParaOnly() {
        P para = factory.createP();
        PPr ppr = factory.createPPr();
        para.setPPr(ppr);
        return para;
    }

    public static P appendParagraphRun(P para,DocxComponent run,DocxPainter docxPainter) {
        if(ComponentTypeEnum.Text.getCode().equals(run.getType())){
            Map<String,Object> attrs = run.getAttrs();
            DocxStyle docxStyle = getStyleByAttrs(attrs,run.getMarks()) ;
            R r = createText(run.getText(), docxStyle);
            para.getContent().add(r);
            return para;
        }else if(ComponentTypeEnum.Image.getCode().equals(run.getType())){
            Map<String,Object> attrs = run.getAttrs();
            DocxStyle docxStyle = getStyleByAttrs(attrs,run.getMarks()) ;
            DocxImage docxImage = new DocxImage(run.getBytes(),docxStyle);
            Map<String,Object> map =  RichTextHelper.getWidthAndHeight(run.getAttr("src").toString(),endpoint,bucketName);
            docxImage.setWidth(Long.valueOf(map.get("width").toString()));
            docxImage.setHeight(Long.valueOf(map.get("height").toString()));
            R r = createImage(docxImage,docxPainter.getWpk());
            para.getContent().add(r);
            return para;
        }else{
            return para;
        }

    }

    /**
     * 创建标题
     *
     * @param styleId  风格id(需要word的标题样式)
     * @param docxText 多克斯文本
     * @return {@link P}
     */
    public static P createHeading(String styleId, DocxText docxText) {
        P p = factory.createP();
        PPr pPr = factory.createPPr();
        p.setPPr(pPr);
        // 标题级别
        PPrBase.PStyle pStyle = factory.createPPrBasePStyle();
        pStyle.setVal(styleId);
        pPr.setPStyle(pStyle);
        //项目符号
        PPrBase.NumPr.Ilvl ilvl = factory.createPPrBaseNumPrIlvl();
        ilvl.setVal(BigInteger.ZERO);
        //编号
        PPrBase.NumPr.NumId numId = factory.createPPrBaseNumPrNumId();
        numId.setVal(BigInteger.ZERO);
        PPrBase.NumPr numPr = factory.createPPrBaseNumPr();
        numPr.setIlvl(ilvl);
        numPr.setNumId(numId);
        pPr.setNumPr(numPr);
        R r = createText(docxText.getText(), docxText.getStyle());
        p.getContent().add(r);
        return p;
    }

    public static P createHeading(String styleId, List<DocxComponent> paragraphList) {
        P p = factory.createP();
        PPr pPr = factory.createPPr();
        p.setPPr(pPr);
        // 标题级别
        PPrBase.PStyle pStyle = factory.createPPrBasePStyle();
        pStyle.setVal(styleId);
        pPr.setPStyle(pStyle);
        //项目符号
        PPrBase.NumPr.Ilvl ilvl = factory.createPPrBaseNumPrIlvl();
        ilvl.setVal(BigInteger.ZERO);
        //编号
        PPrBase.NumPr.NumId numId = factory.createPPrBaseNumPrNumId();
        numId.setVal(BigInteger.ZERO);
        PPrBase.NumPr numPr = factory.createPPrBaseNumPr();
        numPr.setIlvl(ilvl);
        numPr.setNumId(numId);
        pPr.setNumPr(numPr);
        for(DocxComponent run : paragraphList){
            DocxStyle docxStyle = getStyleByAttrs(run.getAttrs(),run.getMarks());
            R r = createText(run.getText(), docxStyle);
            p.getContent().add(r);
        }

        return p;
    }

    /**
     * 创建段落
     *
     * @param docxText 多克斯文本
     * @return {@link P}
     */
    public static P createParagraph(DocxText docxText) {
        P p = addParagraphStyle(factory.createP(), docxText.getStyle());
        R r = createText(docxText.getText(), docxText.getStyle());
        p.getContent().add(r);
        return p;
    }

    public static P createParagraph(List<DocxComponent> paragraphList,DocxPainter docxPainter) {
        P p = factory.createP();
        PPr pPr = factory.createPPr();
        p.setPPr(pPr);
        for(DocxComponent run : paragraphList){

            if(ComponentTypeEnum.Text.getCode().equals(run.getType())){
                Map<String,Object> attrs = run.getAttrs();
                DocxStyle docxStyle = getStyleByAttrs(attrs,run.getMarks()) ;
                R r = createText(run.getText(), docxStyle);
                p.getContent().add(r);
            }else if(ComponentTypeEnum.Image.getCode().equals(run.getType())){
                Map<String,Object> attrs = run.getAttrs();
                DocxStyle docxStyle = getStyleByAttrs(attrs,run.getMarks()) ;
                DocxImage docxImage = new DocxImage(run.getBytes(),docxStyle);
                Map<String,Object> map =  RichTextHelper.getWidthAndHeight(run.getAttr("src").toString(),endpoint,bucketName);
                docxImage.setWidth(Long.valueOf(map.get("width").toString()));
                docxImage.setHeight(Long.valueOf(map.get("height").toString()));
                R r = createImage(docxImage,docxPainter.getWpk());
                p.getContent().add(r);
            }
        }
        return p;




    }

    /**
     * 创建段落
     *
     * @param docxImage 多克斯形象
     * @param wpk       劳动党
     * @return {@link P}
     */
    public static P createParagraph(DocxImage docxImage, WordprocessingMLPackage wpk) {
        P p = addParagraphStyle(factory.createP(), docxImage.getStyle());
        R r = createImage(docxImage, wpk);
        p.getContent().add(r);
        return p;
    }


    public static P createParagraph(DocxComponent docxImageConponent,DocxPainter docxPainter) {
        P p = addParagraphStyle(factory.createP(), getStyleByAttrs(docxImageConponent.getAttrs(),docxImageConponent.getMarks()));
        String fileUrl = Objects.isNull(docxImageConponent.getAttr("src"))?"":docxImageConponent.getAttr("src").toString();

        byte[] bytes = RichTextHelper.fetchFileFromServer(fileUrl);

        DocxImage image = new DocxImage(bytes, getStyleByAttrs(docxImageConponent.getAttrs(),docxImageConponent.getMarks()));
        R r = createImage(image, docxPainter.getWpk());
        p.getContent().add(r);
        return p;
    }

    /**
     * 创建表格
     *
     * @param docxTable 多克斯表
     * @param wpk       劳动党
     * @return {@link Tbl}
     */
    public static Tbl createTable(DocxTable docxTable, WordprocessingMLPackage wpk) {
        if (docxTable.getColumnCount() == 0) {
            return null;
        }
        // 创建空表
        int writableWidthTwips = wpk.getDocumentModel().getSections().get(0).getPageDimensions().getWritableWidthTwips();
        Tbl tbl = TblFactory.createTable(docxTable.getRowCount(), docxTable.getColumnCount(), writableWidthTwips / docxTable.getColumnCount());
        // 调整列宽比例
        adjustTableColWidth(tbl, docxTable.getRows().get(0));
        // 填充表
        for (int i = 0; i < docxTable.getRowCount(); i++) {
            DocxRow docxRow = docxTable.getRows().get(i);
            Tr tr = (Tr) tbl.getContent().get(i);
            for (int j = 0; j < docxTable.getColumnCount(); j++) {
                DocxStyle style = DocxStyle.builder().build();
                style.merge(docxRow.getStyle());
                DocxCell cell = docxRow.getCells().get(j);
                style.merge(cell.getStyle());
                Tc tc = addCellStyle((Tc) tr.getContent().get(j), style);
                tc.getContent().clear();
                //复杂单元格
                if (cell.getPList() != null) {
                    tc.getContent().addAll(cell.getPList().stream().map(p -> addParagraphStyle(p, style)).collect(Collectors.toList()));
                } else {
                    //普通单元格
                    P p = factory.createP();
                    if (cell.getDocxText() != null) {
                        DocxText docxText = cell.getDocxText();
                        style.merge(docxText.getStyle());
                        docxText.setStyle(style);
                        p = createParagraph(docxText);
                    } else if (cell.getDocxImage() != null) {
                        DocxImage docxImage = cell.getDocxImage();
                        style.merge(docxImage.getStyle());
                        docxImage.setStyle(style);
                        p = createParagraph(docxImage, wpk);
                    }
                    tc.getContent().add(p);
                }
            }
        }
        return tbl;
    }

    /**
     * 调整表格列宽
     *
     * @param firstRow           第一行
     */
    private static void adjustTableColWidth(Tbl tbl, DocxRow firstRow) {
        CTTblLayoutType ctTblLayoutType = factory.createCTTblLayoutType();
        ctTblLayoutType.setType(STTblLayoutType.FIXED);
        tbl.getTblPr().setTblLayout(ctTblLayoutType);

        TblGrid tblGrid = tbl.getTblGrid();
        BigDecimal gridColSum = BigDecimal.valueOf(tblGrid.getGridCol().stream().mapToLong(gc -> gc.getW().longValue()).sum());

        List<DocxCell> cells = firstRow.getCells();
        List<BigDecimal> cellWidthList = new ArrayList<>(cells.size());
        cells.forEach(cell -> {
            if (cell.getStyle() != null && cell.getStyle().getCellWidth() != null) {
                cellWidthList.add(BigDecimal.valueOf(cell.getStyle().getCellWidth()));
            } else {
                cellWidthList.add(BigDecimal.valueOf(1000L));
            }
        });
        BigDecimal sum = BigDecimal.valueOf(cellWidthList.stream().mapToLong(BigDecimal::longValue).sum());

        for (int i = 0; i < cells.size(); i++) {
            BigDecimal colWidth = cellWidthList.get(i).divide(sum, 3, RoundingMode.HALF_UP).multiply(gridColSum);
            tblGrid.getGridCol().get(i).setW(colWidth.toBigInteger());
        }
    }

    /**
     * 创建文本
     *
     * @param textToInsert 文本插入
     * @param style        多克斯风格
     * @return {@link R}
     */
    public static R createText(String textToInsert, DocxStyle style) {
        if(StringUtils.isEmpty(textToInsert)) {
            textToInsert =" ";
        }
        R r = addTextStyle(factory.createR(), style);
        String[] textArr = textToInsert.split("<br>");
        for (String t : textArr) {
            Text text = factory.createText();
            text.setValue(t);
            r.getContent().add(text);
            Br br = factory.createBr();
            br.setType(STBrType.TEXT_WRAPPING);
            r.getContent().add(br);
        }
        r.getContent().remove(r.getContent().size() - 1);
        return r;
    }

    /**
     * 创建图像
     *
     * @param docxImage 多克斯形象
     * @param wpk       劳动党
     * @return {@link R}
     */
    public static R createImage(DocxImage docxImage, WordprocessingMLPackage wpk) {
        R r = factory.createR();
        SectPr sectPr = wpk.getMainDocumentPart().getJaxbElement().getBody().getSectPr();
        if (sectPr == null) {
            sectPr = new SectPr();
            wpk.getMainDocumentPart().getJaxbElement().getBody().setSectPr(sectPr);
        }
        // 获取页面宽度相关信息（以EMU为单位）
        SectPr.PgSz pageSz = sectPr.getPgSz();
        BigInteger pageWidthEMU = pageSz.getW();
        SectPr.PgMar pageMar = sectPr.getPgMar();
        long leftMarginEMU = pageMar.getLeft().longValue();
        long rightMarginEMU = pageMar.getRight().longValue();
        long availableWidthEMU = pageWidthEMU.longValue() - leftMarginEMU - rightMarginEMU;
        try {
            BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wpk, docxImage.getBytes());
//            Long emuWidth = docxImage.getWidth() * 914400 / (25220*2);
//            Long emuHeight = docxImage.getHeight() * 914400 / (25220*2);
            Inline inline;
//            if (docxImage.getWidth() != null) {
//                inline = imagePart.createImageInline(docxImage.getFileNameHint(), docxImage.getAltText(), 1, 1, docxImage.getWidth(), false);
//            } else {
//                inline = imagePart.createImageInline(docxImage.getFileNameHint(), docxImage.getAltText(), 1, 1, false);
//            }
            inline = imagePart.createImageInline("test", "test", 1, 1, availableWidthEMU,false);
//            // 设置图片大小
//            CTPositiveSize2D extent = new CTPositiveSize2D();
//
//
//            extent.setCx(emuWidth);
//            extent.setCy(emuHeight);
//            inline.setExtent(extent);
           Drawing drawing = factory.createDrawing();
            r.getContent().add(drawing);
            drawing.getAnchorOrInline().add(inline);
        } catch (Exception e) {
            throw new RuntimeException("wpk create image fail");
        }
        return r;
    }


    // =========================== tool

    public static byte[] readImage(@NonNull InputStream in, boolean close) {
        byte[] result;
        try {
            int available = in.available();
            result = new byte[available];
            int readLength = in.read(result);
            if (readLength != available) {
                throw new IOException("File length is [" + available + " ] but read [" + readLength + "]!");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (close) {
                try {
                    in.close();
                } catch (Exception ignored) {
                }
            }
        }
        return result;
    }
}
